﻿using Cube.Data;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CubeForm.AI
{
    class OLL : IPattenMatch
    {
        Cube.Data.Cube cube;
        PattenManager patten;
        List<Point> SideBlockIndex = new List<Point>
        {
            new Point(1,0),
            new Point(0,1),
            new Point(2,1),
            new Point(1,2)
        };
        List<Point> AngleBlockIndex = new List<Point>
        {
            new Point(0,0),
            new Point(2,0),
            new Point(0,2),
            new Point(2,2)
        };

        public event PattenMatchedDelegate PattenMatched;

        public OLL(Cube.Data.Cube cube)
        {
            this.cube = cube;
            patten = new PattenManager(cube);
        }
        public void Invoke()
        {
            Cross();
            Oll();
            PattenMatched?.Invoke(patten.GetRecord());
        }

        /// <summary>
        /// 顶部十字
        /// </summary>
        private void Cross()
        {
            var top = cube.GetFace(Faces.Up);
            var cross_case = JudgeCrossCase();
            switch (cross_case)
            {
                case OLLCases.Angle:
                    DoCrossPatten();
                    DoCrossPatten();
                    break;
                case OLLCases.Line:
                    DoCrossPatten();
                    break;
                case OLLCases.Dot:
                    DoCrossPatten();
                    patten.U();
                    patten.U();
                    DoCrossPatten();
                    DoCrossPatten();
                    break;
            }
        }

        /// <summary>
        /// OLL
        /// </summary>
        private void Oll()
        {
            var top = cube.GetFace(Faces.Up);
            OLLCases oll_case;
            while ((oll_case = JudgeOLLCase()) != OLLCases.NoNeed)
            {
                Debug.WriteLine("Current OLL Case:" + oll_case);
                DoFishPatten();
                Debug.WriteLine("Fish Patten Done.");
            }
            Debug.WriteLine("OLL Done.\n");
        }

        /// <summary>
        /// 做一次小鱼公式
        /// </summary>
        private void DoFishPatten()
        {
            patten._R(); patten.U(); patten.U(); patten.R();
            patten.U(); patten._R(); patten.U(); patten.R();
        }

        /// <summary>
        /// 做一次顶部十字公式
        /// </summary>
        private void DoCrossPatten()
        {
            patten.F();
            patten.R(); patten.U(); patten._R(); patten._U();
            patten._F();
        }

        /// <summary>
        /// 判断Cross的情况
        /// </summary>
        private OLLCases JudgeCrossCase()
        {
            var is_cross = true;
            var top_color = cube[new PositionVector(0, 0, 1)].Z;
            var top = cube.GetFace(Faces.Up);
            // 检测是否已经是顶部十字
            foreach (var point in SideBlockIndex)
            {
                if(top[point.X,point.Y]!=top_color)
                {
                    is_cross = false;
                }
            }
            if (is_cross)
            {
                Debug.WriteLine("Cross skiped.");
                return OLLCases.Cross;
            }
            var oll_case = OLLCases.Cross;
            for(var i = 0; i < 4; i++)
            {
                top = cube.GetFace(Faces.Up);
                // 判断是否为点、直线、折线
                if (IsLine(top))
                    oll_case = OLLCases.Line;
                if (IsAngle(top))
                    oll_case = OLLCases.Angle;
                if (IsDot(top))
                    oll_case = OLLCases.Dot;
                if(oll_case!= OLLCases.Cross)
                {
                    Debug.WriteLine("Matched Cross case:" + oll_case);
                    return oll_case;
                }
                // 如果都不是，转一下再进行判断
                patten.U();
            }
            throw new Exception();  //不可能存在从四个面看什么都不是的情况
        }
        private OLLCases JudgeOLLCase()
        {
            var is_noneed = true;
            var top_color = cube[new PositionVector(0, 0, 1)].Z;
            var top = cube.GetFace(Faces.Up);
            foreach (var point in AngleBlockIndex)
            {
                if (top[point.X, point.Y] != top_color)
                {
                    is_noneed = false;
                }
            }
            if (is_noneed)
            {
                Debug.WriteLine("OLL skiped.");
                return OLLCases.NoNeed;
            }
            var oll_case = OLLCases.NoNeed;
            for (var i = 0; i < 4; i++)
            {
                top = cube.GetFace(Faces.Up);
                if (IsFish(top))
                    oll_case = OLLCases.Fish;
                if (IsTank(top))
                    oll_case = OLLCases.Tank;
                if (IsDoubleFish(top))
                    oll_case = OLLCases.DoubleFish;
                if (IsCross(top))
                    oll_case = OLLCases.Cross;
                if (oll_case != OLLCases.NoNeed)
                {
                    Debug.WriteLine("Matched OLL case:" + oll_case);
                    return oll_case;
                }
                // 如果都不是，转一下再进行判断
                patten.U();
            }
            Debug.WriteLine(top);
            throw new Exception();  //不可能存在从四个面看什么都不是的情况
        }
        private bool IsLine(CubeColor[,] top)
        {
            var top_color = cube[new PositionVector(0, 0, 1)].Z;
            if (top[1, 0] == top_color && top[1, 2] == top_color) 
            {
                return true;
            }
            return false;
        }
        private bool IsDot(CubeColor[,] top)
        {
            var result = true;
            var top_color = cube[new PositionVector(0, 0, 1)].Z;
            foreach (var point in SideBlockIndex)
            {
                if (top[point.X, point.Y] == top_color)
                {
                    result = false;
                    break;
                }
            }
            return result;
        }
        private bool IsAngle(CubeColor[,] top)
        {
            var top_color = cube[new PositionVector(0, 0, 1)].Z;
            if (top[1, 0] == top_color && top[0, 1] == top_color)
            {
                return true;
            }
            return false;
        }
        private bool IsFish(CubeColor[,] top)
        {
            var top_color = cube[new PositionVector(0, 0, 1)].Z;
            if (top[2, 2] == top_color && top[0, 0] != top_color && top[0, 2] != top_color && top[2, 0] != top_color)
            {
                return true;
            }
            return false;
        }
        private bool IsTank(CubeColor[,] top)
        {
            var top_color = cube[new PositionVector(0, 0, 1)].Z;
            if (top[2, 2] != top_color && top[0, 0] == top_color && top[0, 2] != top_color && top[2, 0] == top_color)
            {
                return true;
            }
            return false;
        }
        private bool IsDoubleFish(CubeColor[,] top)
        {
            var top_color = cube[new PositionVector(0, 0, 1)].Z;
            if (top[2, 2] != top_color && top[0, 0] != top_color && top[0, 2] == top_color && top[2, 0] == top_color)
            {
                return true;
            }
            return false;
        }
        private bool IsCross(CubeColor[,] top)
        {
            var top_color = cube[new PositionVector(0, 0, 1)].Z;
            var front = cube.GetFace(Faces.Front);
            if (top[2, 2] != top_color && top[0, 0] != top_color && top[0, 2] != top_color && top[2, 0] != top_color)
            {
                if (front[0, 0] == top_color && front[0, 2] == top_color)
                    return true;
            }
            return false;
        }

        enum OLLCases
        {
            Line, //直线
            Dot, //点
            Angle, //直角
            Fish, //小鱼
            Tank, //坦克
            DoubleFish, //双鱼
            Cross, //十字
            NoNeed  //无需OLL
        }
    }
}
